"""
Security Audit Logging for Multi-Tenancy

Tracks security-relevant events for compliance and incident investigation:
- Login attempts (success/failure)
- Org switches
- Permission denials
- API key usage
- Suspicious activities

Usage:
    from common.audit_log import audit_log

    audit_log.login_success(user, org, request)
    audit_log.org_switch(user, from_org, to_org, request)
    audit_log.permission_denied(user, org, action, resource, request)
"""

import logging

from django.db import models
from django.utils import timezone

from common.base import BaseModel

logger = logging.getLogger("security.audit")


class SecurityAuditLog(BaseModel):
    """
    Model to store security audit events.

    This is separate from Activity model which tracks business operations.
    SecurityAuditLog tracks authentication and authorization events.
    """

    EVENT_TYPES = (
        ("LOGIN_SUCCESS", "Login Success"),
        ("LOGIN_FAILURE", "Login Failure"),
        ("LOGOUT", "Logout"),
        ("ORG_SWITCH", "Organization Switch"),
        ("TOKEN_REFRESH", "Token Refresh"),
        ("TOKEN_REVOKED", "Token Revoked"),
        ("PERMISSION_DENIED", "Permission Denied"),
        ("CROSS_ORG_ATTEMPT", "Cross-Org Access Attempt"),
        ("API_KEY_USED", "API Key Used"),
        ("API_KEY_INVALID", "Invalid API Key"),
        ("MEMBERSHIP_REVOKED", "Membership Revoked"),
        ("SUSPICIOUS_ACTIVITY", "Suspicious Activity"),
    )

    event_type = models.CharField(max_length=50, choices=EVENT_TYPES, db_index=True)
    user = models.ForeignKey(
        "common.User",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="security_audit_logs",
    )
    org = models.ForeignKey(
        "common.Org",
        on_delete=models.SET_NULL,
        null=True,
        blank=True,
        related_name="security_audit_logs",
    )

    # Event details
    description = models.TextField(blank=True, default="")
    metadata = models.JSONField(default=dict, blank=True)

    # Request information
    ip_address = models.GenericIPAddressField(null=True, blank=True)
    user_agent = models.TextField(blank=True, default="")
    request_path = models.CharField(max_length=500, blank=True, default="")
    request_method = models.CharField(max_length=10, blank=True, default="")

    # Outcome
    success = models.BooleanField(default=True)

    class Meta:
        verbose_name = "Security Audit Log"
        verbose_name_plural = "Security Audit Logs"
        db_table = "security_audit_log"
        ordering = ("-created_at",)
        indexes = [
            models.Index(fields=["event_type", "-created_at"]),
            models.Index(fields=["user", "-created_at"]),
            models.Index(fields=["org", "-created_at"]),
            models.Index(fields=["ip_address"]),
            models.Index(fields=["success", "-created_at"]),
        ]

    def __str__(self):
        return f"{self.event_type} - {self.user} - {self.created_at}"


class AuditLogger:
    """
    Helper class for logging security events.

    Logs to both database (SecurityAuditLog) and Python logger.
    """

    def _get_request_info(self, request):
        """Extract request information for logging."""
        if not request:
            return {}

        # Get IP address
        ip = request.META.get("HTTP_X_FORWARDED_FOR")
        if ip:
            ip = ip.split(",")[0].strip()
        else:
            ip = request.META.get("REMOTE_ADDR")

        return {
            "ip_address": ip,
            "user_agent": request.META.get("HTTP_USER_AGENT", "")[:500],
            "request_path": request.path[:500],
            "request_method": request.method,
        }

    def _log(
        self,
        event_type,
        user=None,
        org=None,
        description="",
        metadata=None,
        success=True,
        request=None,
    ):
        """
        Internal method to create audit log entry.
        """
        request_info = self._get_request_info(request)

        # Log to database
        try:
            SecurityAuditLog.objects.create(
                event_type=event_type,
                user=user,
                org=org,
                description=description,
                metadata=metadata or {},
                success=success,
                **request_info,
            )
        except Exception as e:
            logger.error(f"Failed to create audit log: {e}")

        # Log to Python logger
        log_level = logging.INFO if success else logging.WARNING
        user_id = str(user.id) if user else "anonymous"
        org_id = str(org.id) if org else "none"

        logger.log(
            log_level,
            f"{event_type} | user_id={user_id} | org_id={org_id} | "
            f"ip={request_info.get('ip_address')} | success={success}",
        )

    def login_success(self, user, org, request=None):
        """Log successful login."""
        self._log(
            "LOGIN_SUCCESS",
            user=user,
            org=org,
            description=f"User logged in to {org.name if org else 'platform'}",
            request=request,
        )

    def login_failure(self, email, reason, request=None):
        """Log failed login attempt."""
        from common.models import User

        user = User.objects.filter(email=email).first()

        self._log(
            "LOGIN_FAILURE",
            user=user,
            description=f"Login failed for {email}: {reason}",
            metadata={"email": email, "reason": reason},
            success=False,
            request=request,
        )

    def logout(self, user, org, request=None):
        """Log user logout."""
        self._log(
            "LOGOUT",
            user=user,
            org=org,
            description=f"User logged out",
            request=request,
        )

    def org_switch(self, user, from_org, to_org, request=None):
        """Log organization switch."""
        self._log(
            "ORG_SWITCH",
            user=user,
            org=to_org,
            description=f"Switched from {from_org.name if from_org else 'none'} to {to_org.name}",
            metadata={
                "from_org_id": str(from_org.id) if from_org else None,
                "to_org_id": str(to_org.id),
            },
            request=request,
        )

    def token_refresh(self, user, org, request=None):
        """Log token refresh."""
        self._log(
            "TOKEN_REFRESH",
            user=user,
            org=org,
            description="Token refreshed",
            request=request,
        )

    def token_revoked(self, user, org, reason, request=None):
        """Log token revocation."""
        self._log(
            "TOKEN_REVOKED",
            user=user,
            org=org,
            description=f"Token revoked: {reason}",
            metadata={"reason": reason},
            request=request,
        )

    def permission_denied(self, user, org, action, resource, request=None):
        """Log permission denial."""
        self._log(
            "PERMISSION_DENIED",
            user=user,
            org=org,
            description=f"Permission denied for {action} on {resource}",
            metadata={"action": action, "resource": resource},
            success=False,
            request=request,
        )

    def cross_org_attempt(self, user, user_org, target_org, resource, request=None):
        """Log attempted cross-org data access."""
        self._log(
            "CROSS_ORG_ATTEMPT",
            user=user,
            org=user_org,
            description=f"Attempted to access {resource} in org {target_org.name if target_org else 'unknown'}",
            metadata={
                "user_org_id": str(user_org.id) if user_org else None,
                "target_org_id": str(target_org.id) if target_org else None,
                "resource": resource,
            },
            success=False,
            request=request,
        )

    def api_key_used(self, org, endpoint, request=None):
        """Log API key usage."""
        self._log(
            "API_KEY_USED",
            org=org,
            description=f"API key used for {endpoint}",
            metadata={"endpoint": endpoint},
            request=request,
        )

    def api_key_invalid(self, api_key_prefix, request=None):
        """Log invalid API key attempt."""
        self._log(
            "API_KEY_INVALID",
            description=f"Invalid API key attempted: {api_key_prefix}...",
            metadata={"api_key_prefix": api_key_prefix},
            success=False,
            request=request,
        )

    def membership_revoked(self, user, org, revoked_by=None, request=None):
        """Log when user's org membership is revoked."""
        self._log(
            "MEMBERSHIP_REVOKED",
            user=user,
            org=org,
            description=f"Membership revoked by {revoked_by.email if revoked_by else 'system'}",
            metadata={"revoked_by": str(revoked_by.id) if revoked_by else None},
            request=request,
        )

    def suspicious_activity(self, user, org, activity_type, details, request=None):
        """Log suspicious activity for security review."""
        self._log(
            "SUSPICIOUS_ACTIVITY",
            user=user,
            org=org,
            description=f"Suspicious activity: {activity_type}",
            metadata={"activity_type": activity_type, "details": details},
            success=False,
            request=request,
        )


# Global audit logger instance
audit_log = AuditLogger()
